#include "server.h"

int main(int argc, char* argv[])
{
	fd_set c_rfd;
	struct sockaddr_in serv_addr, client_addr;
	int sockfd, client_sockfd, len, maxFD;

	sockfd = socket(PF_INET, SOCK_STREAM, 0);
	maxFD = sockfd;

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(PORT);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	FD_ZERO(&rfd);

	if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
	{
		fputs("Could not bind to port.\n", stderr);
		exit(1);
	}

	listen(sockfd, MAX_CLIENTS);

	FD_SET(sockfd, &rfd);
	numClients = 0;

	/* We may want to allow user to specify number of rooms */
	buildRooms(numRooms);

	while(1)
	{
		int i;
		c_rfd = rfd;
		
		select(maxFD+1, &c_rfd, NULL, NULL, NULL);

		/* Someone wants to join the server. */
		if(FD_ISSET(sockfd, &c_rfd))
		{
			int len = sizeof(client_addr);

			client_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, (socklen_t *) &len);
			
			if(numClients >= MAX_CLIENTS)
			{
				CODE cmd = SERVERFULL;
printf("Server full.\n");
				write(client_sockfd, &cmd, sizeof(CODE));
				fsync(client_sockfd);
				close(client_sockfd);
				continue;
			}

			FD_SET(client_sockfd, &rfd);
			maxFD = MAX(client_sockfd, maxFD);

			for(i = 0; i < MAX_CLIENTS; i++)
			{
				if(players[i] == NULL)
				{
					int cmd;
printf("Player connected\n");
					numClients++;
					players[i] = calloc(1, sizeof(Player));
					players[i]->ID = client_sockfd;
					cmd = USERNAME;
					write(players[i]->ID, &cmd, sizeof(int));
					cmd = players[i]->ID;
					write(players[i]->ID, &cmd, sizeof(int));
					sendPlayers(players[i]);
					sendRooms(players[i]);
					break;
				}
			}
		}

		/* Someone has something to say */
		for(i = 0; i < MAX_CLIENTS; i++)
		{
			Player* ply = players[i];
			if(ply == NULL) continue;

			if(FD_ISSET(ply->ID , &c_rfd))
			{
				CODE cmd;
				int bytesRead;

				bytesRead = read(ply->ID, &cmd, sizeof(CODE));

				/* Player has diconnected */
				if(bytesRead <= 0)
				{
					if(ply != NULL)
						playerQuit(ply);
					players[i] = NULL;
					continue;
				}

				if(ply == NULL) continue;

				if(cmd & COMMAND)
					switch(cmd)
					{
					case USERNAME:
						readUserName(ply);
						break;
					case JOIN:
						joinPlayerToRoom(ply);
						break;
					case LEAVE:
						if(read(ply->ID, &cmd, sizeof(int)))
							removePlayerFromRoom(ply, cmd);
						else
							connectionLost(ply);
						break;
					case PLAYERS:
						/* TODO: Recieve a room ID, and two players
						 * and give one X. */
						/* Currently players X and O are set up in Join... */
						setupGame();
						break;
				//	case REFRESH:
						/* TODO: Send out rooms and
						 * players again */
						break;
					default:
						printf("Recieved unkown code %d.\n", cmd);
					}
				else
				{
					int r, i;
					int Xmoves = 0;
					int Omoves = 0;
					int winner;
					read(ply->ID, &r, sizeof(int));

					/* Check if they are the next player */
					if(ply->ID != rooms[r]->nextPlayer)
						continue;
					if(played(cmd, r))
						continue;
					printf("Sending move %d for room %d\n", cmd, r);

					rooms[r]->nextPlayer = NEXT(rooms[r], ply->ID);

					/* Check who's move it is and */
					if(ply->ID == rooms[r]->playerX)
						cmd |= X;
					else
						cmd |= O;

					sendMove(cmd, r);

					/* Combine all the X ond O moves for a bit check */
					for(i = 1; i < sizeof(rooms[r]->moves)/sizeof(int); i = i+2)
						Omoves = Omoves | (rooms[r]->moves[i]);
					for(i = 0; i < sizeof(rooms[r]->moves)/sizeof(int); i = i+2) {
						Xmoves = Xmoves | (rooms[r]->moves[i]);
					}

					/* Check for winner */
					winner = checkForWinner(Xmoves, Omoves);
					if(winner) {
						if(winner == X) {
							printf("\nPlayer X wins\n");
						}else {
							printf("\nPlayer O wins\n");
						}

						sendWinner(winner, r);
						rooms[r]->gamesPlayed++;
						resetRoom(r);
						kickAllFromRoom(r);
					}else if(rooms[r]->moves[i-2]) {
						printf("\nCat's game\n");
						sendWinner(CATSGAME, r);
						rooms[r]->gamesPlayed++;
						resetRoom(r);
						kickAllFromRoom(r);
					}
				}
			}
		}
	}
	return 0;
}
